from io import BytesIO
from fastapi.security import OAuth2PasswordRequestForm
from fastapi import APIRouter, Depends, Request, HTTPException, status
from fastapi.responses import StreamingResponse
from typing import Optional, List, Any
from sqlalchemy import delete
from sqlalchemy.orm import joinedload, load_only
from sqlalchemy.future import select
from sqlmodel.ext.asyncio.session import AsyncSession
from schemas.common import RETURN, ListResponse, ListRequest, Filter
from captcha.image import ImageCaptcha
from fastapi_limiter.depends import RateLimiter
from fastapi_cache.decorator import cache
from datetime import datetime

from core.Depend import check_token, has_permission
from database.mysql import get_async_session
from utils import util
from utils.jwtToken import verify_password, generate_token, refresh_Token, get_password_hash

from models.Base import StatusTypeEnum
import models.Base as BaseModel
import models.admin.user.user as UserModel
import models.admin.user.third_user as third_user
import models.admin.system.Admin as AdminModel

import json
import time

from utils.util import random_num
from server.Base import BaseServer
from server.admin.SystemServer import SystemServer
from core.Config import settings
from routers.admin.common import convert_filter_values

router = APIRouter(prefix="/user", tags=["前端-用户管理"])
dataLimit = False



@router.post("/getAccessToken",summary="获取token",response_model=BaseModel.Token)
async def login_for_access_token(
    form_data: OAuth2PasswordRequestForm = Depends(),
    session: AsyncSession = Depends(get_async_session)
) -> BaseModel.Token:
    statement = select(UserModel.Game_User).where(UserModel.Game_User.username == form_data.username)
    result = await session.exec(statement)
    admin_user:UserModel.Game_User = result.scalars().first()
    if admin_user is None or  admin_user.status == BaseModel.StatusTypeEnum.ABNORMAL:
        raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Incorrect username or password",
                headers={"WWW-Authenticate": "Bearer"},
            )
    token = generate_token(form_data.username,settings.SESSION_MAX_AGE)
    return BaseModel.Token(access_token=token['accessToken'], token_type="bearer")


# 规则部分

# 1.规则添加
@router.post("/rule/add",summary="规则添加",response_model=RETURN[Any])
async def rule_add(rule: UserModel.Game_User_Create_Rule, session: AsyncSession = Depends(get_async_session), user: AdminModel.redis_admin = Depends(has_permission("user_rule_add"))):
    # TODO:auths不能重复
    # if rule.auths == "":
    #     return RETURN.fail("菜单编码不能为空")
    state = select(UserModel.Game_User_Rule).where(UserModel.Game_User_Rule.auths == rule.auths).where(UserModel.Game_User_Rule.menu_type == UserModel.MenuTypeEnum.BUTTON)
    result = await session.exec(state)
    isHas:UserModel.Game_User_Rule = result.scalars().first()
    if isHas:
        return RETURN.fail("菜单编码已存在")
    await BaseServer(UserModel.Game_User_Rule).create(rule.dict())
    return RETURN.success("添加成功")

# 2.规则删除
@router.delete("/rule/delete",summary="规则删除",response_model=RETURN[Any])
async def rule_delete(id: int, session: AsyncSession = Depends(get_async_session), user: AdminModel.redis_admin = Depends(has_permission("user_rule_del"))):
    # 初始化一个集合用于存储所有需要删除的菜单ID
    ids_to_delete = set()
    # 定义一个递归函数来收集所有子菜单的ID
    async def collect_child_ids(parent_id: int):
        state = select(UserModel.Game_User_Rule.id).where(UserModel.Game_User_Rule.parent_id == parent_id)
        result = await session.exec(state)
        child_ids = result.scalars().all()
        for child_id in child_ids:
            await collect_child_ids(child_id)  # 递归收集子菜单ID
        ids_to_delete.update(child_ids)

    # 收集主菜单及其所有子菜单的ID
    await collect_child_ids(id)
    ids_to_delete.add(id)

    # TODO: 删除菜单权限关联的角色link
    delete_statement = delete(UserModel.Game_Group_Rule_Link).where(UserModel.Game_Group_Rule_Link.rule_id.in_(ids_to_delete))
    await session.exec(delete_statement)

    delete_statement = delete(UserModel.Game_User_Rule).where(UserModel.Game_User_Rule.id.in_(ids_to_delete))
    result = await session.exec(delete_statement)  # 使用 execute 而不是 exec
    await session.commit()  # 提交事务

    # 检查删除是否成功
    if result.rowcount > 0:
        return RETURN.success(f"删除成功，共删除 {result.rowcount} 个菜单项")
    else:
        return RETURN.fail("删除失败，没有找到对应的菜单项")

# 3.规则编辑
@router.post("/rule/edit",summary="规则编辑",response_model=RETURN[Any])
async def rule_edit(rule: UserModel.Game_User_Edit_Rule, session: AsyncSession = Depends(get_async_session), user: AdminModel.redis_admin = Depends(has_permission("user_rule_edit"))):
    statement = select(UserModel.Game_User_Rule).where(UserModel.Game_User_Rule.auths == rule.auths).where(UserModel.Game_User_Rule.id != rule.id).where(UserModel.Game_User_Rule.menu_type == UserModel.MenuTypeEnum.BUTTON)
    result = await session.exec(statement)
    isHas:UserModel.Game_User_Rule = result.scalars().first()
    if isHas:
        return RETURN.fail("菜单编码已存在")
    await BaseServer(UserModel.Game_User_Rule).update(rule.model_dump())
    return RETURN.success("修改成功")

# 4.规则列表
@router.post("/rule/list",summary="菜单列表")
async def rule_list(request:ListRequest, user: AdminModel.redis_admin = Depends(has_permission("user_rule_list"))):
    result = await BaseServer(UserModel.Game_User_Rule).list(request)
    return RETURN.success("查询成功",result)

# 5.所有规则
@router.get("/rule/all", summary="所有菜单")
@cache(expire=10)
async def rule_all(title:str = '',session: AsyncSession = Depends(get_async_session), user: AdminModel.redis_admin = Depends(has_permission("user_rule_all"))):
    statement = select(UserModel.Game_User_Rule).where(UserModel.Game_User_Rule.title.like(f"%{title}%"))
    result = await session.exec(statement)
    datas = result.scalars().all()
    return RETURN.success("查询成功", datas)

# 6.导出规则
@router.post("/rule/export", summary="导出菜单")
async def rule_export(request:ListRequest,session: AsyncSession = Depends(get_async_session), user: AdminModel.redis_admin = Depends(has_permission("user_rule_export"))):
    data, headers = await BaseServer(UserModel.Game_User_Rule).export(request.filter,request.fields)
    return StreamingResponse(util.generate_large_csv_from_sqlmodel(data), headers=headers)


# 角色组部分

# 1.用户角色组添加
@router.post("/group/add",summary="用户角色组添加",response_model=RETURN[Any])
async def group_add(group: UserModel.Game_User_Create_Group, ruleIds: list[int] = [], session: AsyncSession = Depends(get_async_session), user: AdminModel.redis_admin = Depends(has_permission("user_group_add"))):
    statement = select(UserModel.Game_User_Group).where(UserModel.Game_User_Group.code == group.code)
    result = await session.exec(statement)
    isHas:UserModel.Game_User_Group = result.scalars().first()
    if isHas:
        return RETURN.fail("角色编码已存在")
    
    try:
        group = UserModel.Game_User_Group(**group.model_dump())
        session.add(group)
        # 获取到插入的id
        await session.flush()
        # 再添加新的权限
        add_data = [UserModel.Game_Group_Rule_Link(group_id=group.id, rule_id=ruleId) for ruleId in ruleIds]
        session.add_all(add_data)
        await session.commit()
        return RETURN.success("添加成功")
    except Exception as e:
        await session.rollback()
        return RETURN.fail("添加失败")
    
@router.get("/group/del",summary="用户角色删除")
async def group_delete(id: int,  session: AsyncSession = Depends(get_async_session), user: AdminModel.redis_admin = Depends(has_permission("user_group_del"))):
    # 一并删除角色权限
    try:
        if id <= 3:
            return RETURN.fail("系统默认角色，无法删除")
        # 判断该角色是否已经分配给用户
        statement = select(UserModel.Game_User).where(UserModel.Game_User.group_id == id)
        result = await session.exec(statement)
        isHas:UserModel.Game_User = result.scalars().first()
        if isHas:
            return RETURN.fail("该角色已经分配给用户，无法删除")
        
        # 判断该角色是否有子角色，如果有子角色，不允许删除
        statement = select(UserModel.Game_User_Group).where(UserModel.Game_User_Group.parent_id == id)
        result = await session.exec(statement)
        isHas:UserModel.Game_User_Group= result.scalars().first()
        if isHas:
            return RETURN.fail("该角色有子角色，无法删除，请先删除子角色")

        delete_statement = delete(UserModel.Game_Group_Rule_Link).where(UserModel.Game_Group_Rule_Link.group_id == id)
        await session.exec(delete_statement)

        delete_statement = delete(UserModel.Game_User_Group).where(UserModel.Game_User_Group.id == id)
        await session.exec(delete_statement)

        await session.commit()
        return RETURN.success("删除成功")
    except Exception as e:
        await session.rollback()
        return RETURN.fail(f"删除失败: {str(e)}")

#修改角色
@router.put("/group/edit",summary="用户角色组修改")
async def group_update(group: UserModel.Game_User_Group, ruleIds: list[int] = [], session: AsyncSession = Depends(get_async_session), user: AdminModel.redis_admin = Depends(has_permission("user_group_edit"))):
    statement = select(UserModel.Game_User_Group).where(UserModel.Game_User_Group.code == group.code).where(UserModel.Game_User_Group.id != group.id)
    result = await session.exec(statement)
    existing_role= result.scalars().first()
    if existing_role :
        return RETURN.fail("角色编码已存在")
    try:
        # 查询要更新的角色
        statement = select(UserModel.Game_User_Group).where(UserModel.Game_User_Group.id == group.id)
        result = await session.exec(statement)
        Group = result.scalars().first()

        if not Group:
            return RETURN.fail("角色不存在")
        # 根据id修改
        Group.name = group.name
        Group.code = group.code
        Group.remark = group.remark
        Group.status = group.status
        Group.parent_id = group.parent_id
    
        # 先删除原有的权限
        delete_statement = delete(UserModel.Game_Group_Rule_Link).where(UserModel.Game_Group_Rule_Link.group_id == group.id)
        await session.exec(delete_statement)
        # 再添加新的权限
        add_data = [UserModel.Game_Group_Rule_Link(group_id=group.id, rule_id=ruleId) for ruleId in ruleIds]
        session.add_all(add_data)
        await session.commit()
        return RETURN.success("修改成功")
    except Exception as e:
        await session.rollback()
        return RETURN.fail(f"角色修改失败: {str(e)}")

# 修改角色状态
@router.put("/group/status",summary="角色组状态")
async def group_status(id: int, status: int, user: AdminModel.redis_admin = Depends(has_permission("user_group_change_status"))):
    await BaseServer(UserModel.Game_User_Group).change_status(id, status)
    return RETURN.success("修改成功")

# 查询角色
@router.post("/group/list",summary="角色组列表")
async def group_list(request:ListRequest, user: AdminModel.redis_admin = Depends(has_permission("user_group_list"))):
    fields = ["id", "name","code","status","createtime","updatetime","remark","parent_id"]
    conversion_map = {
        "status": StatusTypeEnum,
    }
    request.filter = await convert_filter_values(conversion_map,request.filter)
    result = await BaseServer(UserModel.Game_User_Group).list(request, fields=fields)
    return RETURN.success("查询成功",result)

# 查询所有角色
@router.post("/group/all",summary="所有角色")
async def group_all(filters: List[Filter] = [], user: AdminModel.redis_admin = Depends(has_permission("user_group_all"))):
    fields = ["id", "name","code","status","createtime","remark","parent_id"]
    conversion_map = {
        "status": StatusTypeEnum,
    }
    filters = await convert_filter_values(conversion_map,filters)
    result = await BaseServer(UserModel.Game_User_Group).all(filters=filters,fields=fields)
    return RETURN.success("查询成功",result)

# 查询角色信息
@router.get("/group/info",summary="角色信息")
async def group_info(id: int, user: AdminModel.redis_admin = Depends(has_permission("user_group_info"))):
    fields = ["id", "name","code","status","createtime","updatetime","remark"]
    result = await BaseServer(UserModel.Game_User_Group).get(id, fields=fields)
    return RETURN.success("查询成功",result)

# 分配权限
@router.post("/group/assign",summary="角色分配权限")
async def group_assign(assignParams:UserModel.assignParams, session: AsyncSession = Depends(get_async_session), user: AdminModel.redis_admin = Depends(has_permission("user_group_assign"))):
     # 先删除原有的权限
    delete_statement = delete(UserModel.Game_Group_Rule_Link).where(UserModel.Game_Group_Rule_Link.group_id == assignParams.id)
    await session.exec(delete_statement)
    await session.commit()
    # 再添加新的权限
    add_data = [UserModel.Game_Group_Rule_Link(group_id=assignParams.id, rule_id=ruleId) for ruleId in assignParams.ruleIds]
    session.add_all(add_data)
    await session.commit()
    return RETURN.success("分配成功")

    
# 查询角色权限
@router.get("/group/rule",summary="角色权限")
async def group_rule(id: int, session: AsyncSession = Depends(get_async_session), user: AdminModel.redis_admin = Depends(has_permission("user_group_rule"))):
    # TODO:如果id为1，返回所有权限的id
    if id == 1:
        fields = [UserModel.Game_User_Group.id]
        statement = select(UserModel.Game_User_Group).options(load_only(*fields))
        result = await session.exec(statement)
        datas = result.scalars().all()
        ids = [item.id for item in datas]
        return RETURN.success("查询成功",ids)
        
    statement = select(UserModel.Game_Group_Rule_Link.rule_id).where(UserModel.Game_Group_Rule_Link.group_id == id)
    result = await session.exec(statement)
    datas = result.scalars().all()
    return RETURN.success("查询成功",datas)

# 查询所有角色权限
@router.get("/group/group_rule",summary="所有角色权限")
async def group_rule(id:Optional[int] = 1, session: AsyncSession = Depends(get_async_session), user: AdminModel.redis_admin = Depends(has_permission("user_group_rule_all"))):
    fields = [
        UserModel.Game_User_Rule.parent_id,
        UserModel.Game_User_Rule.id,
        UserModel.Game_User_Rule.title,
        UserModel.Game_User_Rule.menu_type
    ]
    # 根据角色id查询角色权限
    if id == 1:
        statement = select(UserModel.Game_User_Rule).options(load_only(*fields))
        result = await session.exec(statement)
        datas = result.scalars().all()
    else:
        statement = select(UserModel.Game_Group_Rule_Link.rule_id).where(UserModel.Game_Group_Rule_Link.rule_id == id)
        result = await session.exec(statement)
        menu_datas = result.scalars().all()
        menu_ids = [item for item in menu_datas]
        statement = select(UserModel.Game_User_Rule).where(UserModel.Game_User_Rule.id.in_(menu_ids)).options(load_only(*fields))
        result = await session.exec(statement)
        datas = result.scalars().all()
    return RETURN.success("查询成功", datas)

# 导出角色
@router.post("/group/export",summary="导出角色")
async def group_export(request:ListRequest, user: AdminModel.redis_admin = Depends(has_permission("user_group_export"))):
    data, headers = await BaseServer(UserModel.Game_User_Group).export(request.filter,request.fields)
    return StreamingResponse(util.generate_large_csv_from_sqlmodel(data), headers=headers)

# 用户部分

# 1.增加用户
@router.post("/user/add",summary="用户添加",response_model=RETURN[Any])
async def user_add(user: UserModel.Game_User_Create,session: AsyncSession = Depends(get_async_session), cahce_user: AdminModel.redis_admin = Depends(has_permission("user_user_add"))):
    #判断 userName 或者 mobile 是否存在
    state = select(UserModel.Game_User).where(UserModel.Game_User.username == user.username)
    result = await session.exec(state)
    obj = result.scalars().first()
    if obj:
        return RETURN.fail("用户名已存在")
    
    state = select(UserModel.Game_User).where(UserModel.Game_User.mobile == user.mobile)
    result = await session.exec(state)
    obj = result.scalars().first()
    if obj:
        return RETURN.fail("手机号已存在")
    
    state = select(UserModel.Game_User).where(UserModel.Game_User.email == user.email)
    result = await session.exec(state)
    obj = result.scalars().first()
    if obj:
        return RETURN.fail("邮箱已存在")
    
    if user.birthday:
        user.birthday = datetime.strptime(user.birthday, "%Y-%m-%dT%H:%M:%S.%fZ").timestamp()
    if user.prevtime:
        user.prevtime = datetime.strptime(user.prevtime, "%Y-%m-%dT%H:%M:%S.%fZ").timestamp()
    if user.jointime:
        user.jointime = datetime.strptime(user.jointime, "%Y-%m-%dT%H:%M:%S.%fZ").timestamp()
    
    add_user = UserModel.Game_User(**user.dict())

    user.password =  get_password_hash(user.password)
    await BaseServer(UserModel.Game_User).create(add_user.dict())
    return RETURN.success("添加成功")

# 2.删除用户
@router.delete("/user/del",summary="用户删除",response_model=RETURN[Any])
async def admin_delete(id: int,request: Request, session: AsyncSession = Depends(get_async_session), user: AdminModel.redis_admin = Depends(has_permission("user_user_del"))):
    # 先获取用户信息
    fields = ["type"]
    user = await BaseServer(UserModel.Game_User).get(id, fields=fields)
    if user.type == UserModel.UserType.THIRD_PARTY:
        state = delete(third_user.Game_Third_User).where(third_user.Game_Third_User.user_id == id)
        await session.exec(state)
    await BaseServer(UserModel.Game_User).delete(id)
    # TODO: redis缓存删除
    await request.app.state.cache.delete(f"gameuser:{user.username}")
    await request.app.state.cache.delete(f"gameuser:{user.username}_auths")
    return RETURN.success("删除成功")

# 3.修改用户
@router.put("/user/edit",summary="用户修改",response_model=RETURN[Any])
async def user_update(edit_user: UserModel.Game_User_Edit,session: AsyncSession = Depends(get_async_session), user: AdminModel.redis_admin = Depends(has_permission("user_user_edit"))):
    state = select(UserModel.Game_User).where(UserModel.Game_User.mobile == edit_user.mobile).where(UserModel.Game_User.id != edit_user.id)
    result = await session.exec(state)
    obj = result.scalars().first()
    if obj:
        return RETURN.fail("手机号已存在")

    # 如果头像为空，删除该字段
    if not edit_user.avatar:
        del edit_user.avatar

    if edit_user.birthday:
        edit_user.birthday = datetime.strptime(edit_user.birthday, "%Y-%m-%dT%H:%M:%S.%fZ").timestamp()
    if edit_user.prevtime:
        edit_user.prevtime = datetime.strptime(edit_user.prevtime, "%Y-%m-%dT%H:%M:%S.%fZ").timestamp()
    if edit_user.jointime:
        edit_user.jointime = datetime.strptime(edit_user.jointime, "%Y-%m-%dT%H:%M:%S.%fZ").timestamp()
    
    add_user = UserModel.Game_User(**edit_user.model_dump())

    await BaseServer(UserModel.Game_User).update(add_user.model_dump())
    return RETURN.success("修改成功")

# 4.查询管理员
@router.post("/user/list",summary="管理员列表",response_model=RETURN[ListResponse[Any]])
async def user_list(request:ListRequest, user: AdminModel.redis_admin = Depends(has_permission("user_user_list"))):
    fields = [
        "id","username","nickname","mobile","loginip",
        "avatar","logintime","status","gender","birthday","bio","money","score",
        "createtime","email","successions","maxsuccessions",
        "loginfailure","prevtime","loginip","joinip","jointime"
    ]
    conversion_map = {
        "status": BaseModel.StatusTypeEnum
    }

    request.filter = await convert_filter_values(conversion_map,request.filter)
    relations = {
        "group": ["id", "name"]
    }
    data = await BaseServer(UserModel.Game_User).list(request, fields=fields, relations=relations)
    return RETURN.success("查询成功",data)

# 5.批量删除
@router.delete("/user/batch_del",summary="管理员批量删除",response_model=RETURN[Any])
async def user_batch_delete(ids: List[int], user: AdminModel.redis_admin = Depends(has_permission("user_user_batch_del"))):
    await BaseServer(UserModel.Game_User).batch_delete(ids)
    return RETURN.success("删除成功")


# 5.修改密码
@router.put("/user/password",summary="修改密码",response_model=RETURN[Any])
async def user_password(id: int, password: str, session: AsyncSession = Depends(get_async_session), user: AdminModel.redis_admin = Depends(has_permission("user_user_reset_password"))):
    password = get_password_hash(password)
    await BaseServer(UserModel.Game_User).update({"id":id,"password":password})
    return RETURN.success("修改成功")

# 6.修改上传头像
@router.put("/user/avatar",summary="修改头像",response_model=RETURN[Any])
async def user_avatar(id: int, avatar: str, session: AsyncSession = Depends(get_async_session), user: AdminModel.redis_admin = Depends(has_permission("user_user_edit_avatar"))):
    await BaseServer(UserModel.Game_User).update({"id":id,"avatar":avatar})
    return RETURN.success("修改成功")

# 7.修改用户状态
@router.put("/user/status",summary="修改用户状态",response_model=RETURN[Any])
async def user_status(id: int, status: int, session: AsyncSession = Depends(get_async_session), user: AdminModel.redis_admin = Depends(has_permission("user_user_change_status"))):
    await BaseServer(UserModel.Game_User).change_status(id, status)
    return RETURN.success("修改成功")

# 8.导出用户
@router.post("/user/export",summary="导出用户")
async def user_export(request:ListRequest, user: AdminModel.redis_admin = Depends(has_permission("user_user_export"))):
    data, headers = await BaseServer(UserModel.Game_User).export(request.filter,request.fields)
    return StreamingResponse(util.generate_large_csv_from_sqlmodel(data), headers=headers)